001 /*
002 * Copyright (c) 2005 Stephen J. McConnell
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.metro.tools;
020
021 import java.net.URI;
022 import java.net.URISyntaxException;
023
024 import net.dpml.component.Directive;
025
026 import net.dpml.metro.info.PartReference;
027 import net.dpml.metro.data.ValueDirective;
028 import net.dpml.metro.data.LookupDirective;
029 import net.dpml.metro.data.NullDirective;
030 import net.dpml.metro.data.FeatureDirective;
031 import net.dpml.metro.info.EntryDescriptor;
032 import net.dpml.metro.info.Type;
033
034 import net.dpml.lang.Value;
035
036 import org.apache.tools.ant.BuildException;
037
038 /**
039 * A simple part datatype.
040 *
041 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
042 * @version 1.1.0
043 */
044 public class EntryDataType extends ValueDataType implements PartReferenceBuilder
045 {
046 private String m_key;
047 private ClassLoader m_classloader;
048 private String m_spec;
049 private int m_feature = -1;
050 private boolean m_validate = true;
051
052 /**
053 * Set the key that this directive qualifies.
054 * @param key the context entry key
055 */
056 public void setKey( final String key )
057 {
058 m_key = key;
059 }
060
061 /**
062 * Set the lookup attribute value.
063 * @param spec the service classname
064 */
065 public void setLookup( final String spec )
066 {
067 m_spec = spec;
068 }
069
070 /**
071 * Set the validation flag.
072 * @param flag if false entry validation is disabled
073 */
074 public void setValidate( final boolean flag )
075 {
076 m_validate = flag;
077 }
078
079 /**
080 * Set the feature that this directive references.
081 * @param feature the component feature
082 */
083 public void setFeature( String feature )
084 {
085 if( null != m_spec )
086 {
087 final String error =
088 "Attributes 'feature' and 'lookup' are mutually exlusive.";
089 throw new BuildException( error );
090 }
091 try
092 {
093 m_feature = FeatureDirective.getFeatureForName( feature );
094 }
095 catch( IllegalArgumentException e )
096 {
097 final String error = e.getMessage();
098 throw new BuildException( error );
099 }
100 }
101
102 //---------------------------------------------------------------------
103 // Builder
104 //---------------------------------------------------------------------
105
106 /**
107 * Return a uri identitifying the builder.
108 *
109 * @return the builder uri
110 */
111 public URI getBuilderURI()
112 {
113 return PART_BUILDER_URI;
114 }
115
116 //---------------------------------------------------------------------
117 // PartReferenceBuilder
118 //---------------------------------------------------------------------
119
120 /**
121 * Return the key identifying the part that this builder is building.
122 * @return the key
123 */
124 public String getKey()
125 {
126 if( null == m_key )
127 {
128 final String error =
129 "Missing 'key' attribute declaration.";
130 throw new ConstructionException( error );
131 }
132 return m_key;
133 }
134
135 /**
136 * Return the lookup service classname.
137 * @return the classname
138 */
139 private String getLookupAttribute()
140 {
141 return m_spec;
142 }
143
144 /**
145 * Build a part reference.
146 * @param classloader the classloader to use
147 * @param type the underlying component type
148 * @return the part reference
149 */
150 public PartReference buildPartReference( ClassLoader classloader, Type type )
151 {
152 String key = getKey();
153 if( !m_validate )
154 {
155 Directive directive = new NullDirective();
156 return new PartReference( key, directive );
157 }
158 else
159 {
160 String spec = getLookupAttribute();
161 if( null != spec )
162 {
163 Directive directive = new LookupDirective( spec );
164 return new PartReference( key, directive );
165 }
166 else if( m_feature > -1 )
167 {
168 Directive directive = new FeatureDirective( key, m_feature );
169 return new PartReference( key, directive );
170 }
171 else
172 {
173 Directive directive = getValueDirective( classloader, type );
174 return new PartReference( key, directive );
175 }
176 }
177 }
178
179 /**
180 * Return a urn identitifying the part handler for this builder.
181 *
182 * @return the part handler uri
183 */
184 public URI getPartHandlerURI()
185 {
186 return PART_HANDLER_URI;
187 }
188
189 //---------------------------------------------------------------------
190 // implementation
191 //---------------------------------------------------------------------
192
193 /**
194 * Return the value directive.
195 * @param classloader the classloader to use
196 * @param type the underlying component type
197 * @return the value directive
198 */
199 public ValueDirective getValueDirective( ClassLoader classloader, Type type )
200 {
201 String key = getKey();
202 String classname = getClassname();
203 if( null != classname )
204 {
205 try
206 {
207 classloader.loadClass( classname );
208 }
209 catch( ClassNotFoundException e )
210 {
211 final String error =
212 "Entry directive overriding class ["
213 + classname
214 + "] is unknown.";
215 throw new BuildException( error, e );
216 }
217 }
218
219 String method = getMethodName();
220
221 if( null != type )
222 {
223 EntryDescriptor entry = type.getContextDescriptor().getEntryDescriptor( key );
224 if( null == entry )
225 {
226 final String error =
227 "The value key ["
228 + key
229 + "] is unknown relative to the component type ["
230 + type.getInfo().getClassname()
231 + "].";
232 throw new ConstructionException( error );
233 }
234 else if( null == classname )
235 {
236 classname = entry.getClassname();
237 }
238 }
239
240 if( null == classname )
241 {
242 final String error =
243 "Missing 'class' attribute for entry key ["
244 + key
245 + "].";
246 throw new ConstructionException( error );
247 }
248
249 String value = getValue();
250 if( null != value )
251 {
252 return new ValueDirective( classname, method, value );
253 }
254 else
255 {
256 ValueBuilder[] params = getValueBuilders();
257 Value[] values = new Value[ params.length ];
258 for( int i=0; i<params.length; i++ )
259 {
260 ValueBuilder p = params[i];
261 values[i] = p.buildValue( classloader );
262 }
263 return new ValueDirective( classname, method, values );
264 }
265 }
266
267 //---------------------------------------------------------------------
268 // static utilities
269 //---------------------------------------------------------------------
270
271 private static final URI PART_HANDLER_URI = setupURI( "artifact:part:dpml/metro/dpml-metro-runtime#1.0.1" );
272 private static final URI PART_BUILDER_URI = setupURI( "artifact:part:dpml/metro/dpml-metro-tools#1.1.0" );
273
274 /**
275 * Utility function top create a static uri.
276 * @param spec the uri spec
277 * @return the uri value
278 */
279 protected static URI setupURI( String spec )
280 {
281 try
282 {
283 return new URI( spec );
284 }
285 catch( URISyntaxException ioe )
286 {
287 return null;
288 }
289 }
290 }
291